package com.lg.concurrent.lock;

import com.lg.domain.Base;
import lombok.SneakyThrows;
import org.openjdk.jol.info.ClassLayout;

import java.util.concurrent.CountDownLatch;

/**
 * 锁的升级过程
 * object header 是 mark world
 * 前两个object header 共级8字节 64位，标识的是锁的状态和gc的标志
 * 第三个object header 元数据指针，及class对应的元空间位置的指针
 * 数组对象才会有第四个object header，表示数组的长度
 * 再下面是实例数据
 * 再往下是对齐补充

 * value 十六进制  二进制 十进制 应该倒着看
 * 01 无锁      00无偏向锁
 * 01 无锁      01有偏向锁
 * 00 轻量级锁
 * 10 重量级锁
 * 11 gc的标志

 * 应用启动刚开始new出来的对象是无锁转态，jvm默认应用启动后4秒开起偏向锁，4秒后new出来的对象是带有匿名偏向锁的
 * 可以在启动命令上加上参数让取消这4s 的等待，也可以增加参数去掉偏向锁
 *
 * 单线程对争抢无锁对象直接变成轻量级锁  释放锁之后变成无锁
 *
 * 应用4s后new出来的对象都是匿名偏向锁，
 * 单线程竞争只有会将线程id写到对象头里面，变成偏向锁。    这个单线程释放锁之后，依然为偏向锁，此刻拥有锁的线程已经死掉，但是头部依然存在这个线程的id
 *
 * 紧接着这个线程又来竞争这把锁，直接拿到，升级为轻量级锁    执行逻辑，释放这把锁变为无锁
 * 再次争抢这把锁，同上
 *
 * 当多个（两个）线程同时竞争一把锁的时候，直接升级成重锁，释放锁后 对象依然是重锁，对象头也不变！！！！？？？
 * 释放锁之后，在有一个单线程去拿这个重锁，依然是重锁，释放后重锁依然存在
 *
 */
public class LockUpgrade {

    @SneakyThrows
    public static void main(String[] args) {
        Base base = new Base();
        System.out.println("无锁（00 01）" + ClassLayout.parseInstance(base).toPrintable());
        printLine();

        Thread.sleep(4000);
        Base base2 = new Base();
        System.out.println("匿名偏向锁，但没有标记线程（01 01）" + ClassLayout.parseInstance(base2).toPrintable());
        printLine();

        Thread thread1 = new Thread(() -> {
            Base base3 = new Base();
            System.out.println("验证是应用，不是线程4s，匿名偏向锁（01 01）" + ClassLayout.parseInstance(base3).toPrintable());
        });
        thread1.start();
        thread1.join();
        printLine();


        synchronized (base) {
            System.out.println("base（当前为无锁）当只有一个线程竞争的时候，直接升级为轻量级锁（00 指针）" + ClassLayout.parseInstance(base).toPrintable());
        }
        System.out.println("base当上面锁释放后，直接变成无锁" + ClassLayout.parseInstance(base).toPrintable());
        printLine();


        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                synchronized (base2) {
                    System.out.println("base2（当前为当匿名偏向锁），只有一个线程的时候竞争的时候，变成偏向锁（01 01 thread-id）" + ClassLayout.parseInstance(base2).toPrintable());
                }
            }
        });
        thread2.start();
        thread2.join();
        Thread.sleep(2000);
        System.out.println("base2当上面单线程竞争三次释放锁后，线程已经死掉了，偏向锁还在（01 01 thread-id）" + ClassLayout.parseInstance(base2).toPrintable());
        printLine();


        new Thread(() -> {
            for (int i = 0; i < 2; i++) {
                synchronized (base2) {
                    System.out.println(Thread.currentThread().getName() + "当另一个线程来竞争base2（目前为偏向锁，标记thread-id），直接升级为轻量级锁（00 指针）" + ClassLayout.parseInstance(base2).toPrintable());
                }
            }
            System.out.println(Thread.currentThread().getName() + "此线程没有死，释放锁后，变为无锁！！！" + ClassLayout.parseInstance(base2).toPrintable());
        }).start();
        Thread.sleep(2000);
        synchronized (base2) {
            System.out.println( "再次对base2（目前为无锁）进行竞争，直接升级为轻量级锁（00 指针）" + ClassLayout.parseInstance(base2).toPrintable());
        }
        printLine();

        CountDownLatch countDownLatch = new CountDownLatch(1);
        Thread[] threads = new Thread[3];
        Base base3 = new Base();
        int num = 2;
        for (int i = 0; i < num; i++) {
            threads[i] = new Thread(() -> {
                try {
                    countDownLatch.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (base3) {
                    System.out.println("多线程竞争"+Thread.currentThread().getName() + "，直接升级为重锁" + ClassLayout.parseInstance(base3).toPrintable());
                }
                System.out.println("多线程竞争"+Thread.currentThread().getName() + "释放锁之后，对象头没变" + ClassLayout.parseInstance(base3).toPrintable());
            });
        }
        for (int i = 0; i < num; i++) {
            threads[i].start();
        }
        countDownLatch.countDown();
        for (int i = 0; i < num; i++) {
            threads[i].join();
        }
        System.out.println( "上述线程死后，重锁依然存在" + ClassLayout.parseInstance(base3).toPrintable());
        printLine();


        synchronized (base3){
            System.out.println("单线程竞争 上面释放的重锁，还是重锁，不会再降级" + ClassLayout.parseInstance(base3).toPrintable());
        }


    }



    public static void printLine(){
        System.out.println();
        System.out.println();
        System.out.println("=====================================");
        System.out.println();
        System.out.println();
        System.out.println();
    }

}
